package bma.common.langutil.packagefw;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import bma.common.langutil.ai.stack.AIStack;
import bma.common.langutil.ai.vm.AIVM;

public class PackageManager {

	private Set<PackageHandler> handlers = Collections
			.synchronizedSet(new HashSet<PackageHandler>());
	private Set<ClassLoader> loaders = Collections
			.synchronizedSet(new HashSet<ClassLoader>());

	public void addHandler(final PackageHandler handler) {
		if (handlers.add(handler)) {
			List<ClassLoader> list = new ArrayList<ClassLoader>(loaders);
			for (ClassLoader cl : list) {
				open(handler, cl);
			}
		}
	}

	public void removeHandler(final PackageHandler handler) {
		if (handlers.remove(handler)) {
			List<ClassLoader> list = new ArrayList<ClassLoader>(loaders);
			for (ClassLoader cl : list) {
				close(handler, cl);
			}
		}
	}

	public void start() {
		addClassLoader(null, Thread.currentThread().getContextClassLoader());
	}

	public void stop() {
		List<PackageHandler> plist = new ArrayList<PackageHandler>(handlers);
		handlers.clear();

		List<ClassLoader> list = new ArrayList<ClassLoader>(loaders);
		loaders.clear();

		for (PackageHandler handler : plist) {
			for (ClassLoader cl : list) {
				close(handler, cl);
			}
		}
	}

	protected void close(PackageHandler handler, ClassLoader cl) {
		try {
			handler.closeClassLoader(this, cl);
		} catch (Exception e) {
		}
	}

	protected void open(PackageHandler handler, ClassLoader cl) {
		try {
			handler.openClassLoader(this, cl);
		} catch (Exception e) {
		}
	}

	protected void addClassLoader(final AIStack<Boolean> stack,
			final ClassLoader cl) {
		if (loaders.add(cl)) {
			Runnable run = new Runnable() {

				@Override
				public void run() {
					List<PackageHandler> list = new ArrayList<PackageHandler>(
							handlers);
					for (PackageHandler handler : list) {
						open(handler, cl);
					}
					if (stack != null) {
						stack.success(true);
					}
				}

			};
			if (stack == null) {
				run.run();
			} else {
				AIVM.current().execute(null, run);
			}
		}
	}

	public void removeClassLoader(final AIStack<Boolean> stack,
			final ClassLoader cl) {
		if (loaders.remove(cl)) {
			AIVM.current().execute(null, new Runnable() {

				@Override
				public void run() {
					List<PackageHandler> list = new ArrayList<PackageHandler>(
							handlers);
					for (PackageHandler handler : list) {
						close(handler, cl);
					}
					if (stack != null) {
						stack.success(true);
					}
				}

			});
		}
	}

}
